/** @file dataset.cc
 *
 *  @author Dongryeol Lee (drselee@gmail.com)
 */

#include <boost/mpi.hpp>
#include "core/data/dataset.h"

namespace core {
namespace data {

Dataset::~Dataset() {
}

void Dataset::FindPartition_(
  int file_length, int num_partitions, std::ifstream &is,
  bool attribute_header_present,
  std::vector <
  std::pair<int, int> > *partition_out) {

  // The last begin position to start from.
  int last_begin_pos = 0;
  char check;

  if(attribute_header_present) {

    // Find the first '\n' which constitutes the list of attribute
    // names.
    do {
      is.seekg(last_begin_pos);
      is.read(&check, 1);
      last_begin_pos++;
    }
    while(check != '\n');
  }

  // Compute the chunk size.
  int chunk_size = (file_length - last_begin_pos) / num_partitions;

  for(int i = 0; i < num_partitions - 1; i++) {
    int trial_end_pos = last_begin_pos + chunk_size - 1;
    int backup_trial_end_pos = trial_end_pos;
    is.clear();
    is.seekg(trial_end_pos);
    while(trial_end_pos > last_begin_pos) {
      is.read(&check, 1);
      if(check == '\n') {
        break;
      }
      trial_end_pos--;
      is.clear();
      is.seekg(trial_end_pos);
    }

    // If going backward failed, then go forward.
    if(trial_end_pos == last_begin_pos) {
      trial_end_pos = backup_trial_end_pos;
      is.clear();
      is.seekg(trial_end_pos);
      while(trial_end_pos > last_begin_pos) {
        is.read(&check, 1);
        if(check == '\n') {
          break;
        }
        trial_end_pos++;
        is.clear();
        is.seekg(trial_end_pos);
      }
    }

    partition_out->resize(partition_out->size() + 1);
    partition_out->back() =
      std::pair<int, int>(
        last_begin_pos, trial_end_pos - last_begin_pos + 1);
    last_begin_pos = trial_end_pos + 1;
  }
  partition_out->resize(partition_out->size() + 1);
  partition_out->back() =
    std::pair < int, int > (
      last_begin_pos, file_length - last_begin_pos);
}

void Dataset::SetupDefaultAttributeList_(int num_attributes_in) {
  if(num_attributes_in != static_cast<int>(attribute_names_.size())) {
    attribute_names_.clear();
    for(int i = 0; i < num_attributes_in; i++) {
      std::stringstream att_str;
      att_str << "att_" << i;
      attribute_names_.push_back(att_str.str());
    }
  }
  raw_point_attribute_indices_.zeros(num_attributes_in - 1);
  raw_target_attribute_indices_.zeros(1);
  for(int i = 0; i < num_attributes_in; i++) {
    // By default, everything except for the last is the raw point.
    if(i < num_attributes_in - 1) {
      raw_point_attribute_indices_[i] = i;
    }
    else {
      raw_target_attribute_indices_[0] = i;
    }
  }
}

void Dataset::Init(
  boost::mpi::communicator &world, int num_attributes_in, int num_points_in) {
  this->Init(num_attributes_in, num_points_in);
  world.barrier();
}

bool Dataset::is_nominal_attribute(int attribute_index_in) const {
  return nominal_values_[ attribute_index_in ].size() > 0;
}

int Dataset::num_attributes() const {
  return static_cast<int>(attribute_names_.size());
}

int Dataset::num_point_attributes() const {
  return static_cast<int>(raw_point_attribute_indices_.n_elem);
}
}
}
